/*
 *@file:start.S
 *@description:演示重定位（在SRAM内部重定位）
 */

#define WTCON       0xE2700000
#define SVC_STACK   0xD0037D80

//把_start链接属性改为外部，这样其他文件就可以看见_start
.global _start
_start:
    //PWR_EN置锁
    ldr r0,=0xE010E81C
    ldr r1,[r0]
    orr r1,r1,#0x300
    orr r1,r1,#0x1
    str r1,[r0]

    //第1步：关看门狗
    ldr r0, = WTCON
    ldr r1, = 0x0
    str r1, [r0]

    //第2步：设置SVC栈
    ldr sp,=SVC_STACK

    //第3步：开/关iCache
    //读出cp15的c1到r0中
    mrc p15,0,r0,c1,c0,0;
    //bit12置0，关icache
    #bic r0,r0,#(1<<12)
    //bit12置1，开icache
    orr r0,r0,#(1<<12)
    mcr p15,0,r0,c1,c0,0;

    //第4步：重定位
    //adr指令用于加载_start当前运行地址
    //adr加载时就叫短加载
    adr r0,_start
    //ldr指令用于加载_start的链接地址:0xD0024000
    //ldr加载时如果目标寄存器是pc就叫长跳转，
    //如果目标寄存器是r1等就叫长加载
    ldr r1, = _start
    //bss段的起始地址
    //就是我们重定位代码的结束地址，
    //重定位只需重定位代码段和数据段即可
    ldr r2, = bss_start
    //比较_start的运行时地址和链接地址是否相等
    cmp r0, r1
    //如果相等，说明不需要重定位，所以跳过copy_loop,直接clean_bss
    //如果不相等，说明需要重定位，那么直接执行下面的copy_loop进行重定位
    //重定位完成后继续执行clean_bss
    beq clean_bss

    //用汇编实现一个while循环
copy_loop:
    //源
    ldr r3, [r0], #4
    //目的,这两句代码就完成了4个字节内容的拷贝
    str r3, [r1], #4
    //r1和r2都是用ldr加载的，都是链接地址，所以r1不断+4总能等于r2
    cmp r1,  r2
    bne copy_loop

    //清bss段，其实就是在链接地址处把bss段全部清零
clean_bss:
    ldr r0, =bss_start
    ldr r1, =bss_end
    //如果r0等于r1,说明bss段为空，直接下去
    cmp r0,r1
    //清除bss完之后的地址
    beq run_on_dram
    mov r2,#0

clear_loop:
    //先将r2中的值放入r0所指向的内存地址
    //（r0中的值作为内存地址）
    str r2, [r0], #4
    //然后r0=r0+4
    cmp r0,r1
    bne clear_loop

run_on_dram:
    // 长跳转到led_blink开始第二阶段
    // ldr指令实现长跳转
    ldr pc,=led_blink

    // 从这里之后就可以开始调用C程序了
    // bl指令实现短跳转
    //bl led_blink  

    b .
